package com.gsbelarus.gedemin.lib.ui.activity.drawer;

import android.content.res.Configuration;
import android.graphics.PorterDuff;
import android.graphics.drawable.Drawable;
import android.os.Build;
import android.os.Bundle;
import android.support.v4.view.GravityCompat;
import android.support.v4.widget.DrawerLayout;
import android.support.v7.app.ActionBarDrawerToggle;
import android.support.v7.widget.DefaultItemAnimator;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.support.v7.widget.Toolbar;
import android.util.Log;
import android.util.TypedValue;
import android.view.Gravity;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.widget.FrameLayout;
import android.widget.LinearLayout;

import com.gsbelarus.gedemin.lib.R;
import com.gsbelarus.gedemin.lib.ui.activity.SyncActivityModel;
import com.gsbelarus.gedemin.lib.ui.activity.drawer.adapter.DrawerAdapter;
import com.gsbelarus.gedemin.lib.ui.activity.drawer.adapter.table.DrawerItem;
import com.gsbelarus.gedemin.lib.ui.activity.drawer.adapter.table.DrawerMainItem;
import com.gsbelarus.gedemin.lib.ui.activity.drawer.adapter.table.DrawerProfile;

import java.util.List;

abstract public class SyncActivityDrawerModel extends SyncActivityModel implements DrawerAdapter.OnItemClickListener {

    private LinearLayout drawerLayout;
    private FrameLayout contentLayout;
    private RecyclerView drawerListMenu;
    private DrawerAdapter drawerAdapter;
    private DrawerLayout drawer;
    private ActionBarDrawerToggle mDrawerToggle;
    private OnDrawerItemClickListener onDrawerItemClickListener;

    private DrawerItem selectedMainItem;
    private DrawerItem selectedOtherItem;
    private boolean onClick;

    private int defaultTextColor;
    private int defaultCounterTextColor;

    private int contentPaddingTop;

    /**
     * @return id View для отрисовки в активити
     */
    @Override
    final public int getViewResource() {
        return R.layout.actvt_drawer;
    }

    /**
     * @return id layout-а для контента
     */
    abstract public int getContentResource();

    @Override
    final protected boolean isShowingToolbar() {
        return false;
    }

    public void onDrawerStateChanged(int newState) {
    }

    public void onDrawerSlide(View drawerView, float slideOffset) {
    }

    public void onDrawerOpened(View drawerView) {
    }

    public void onDrawerClosed(View drawerView) {
    }

    /**
     * вызывается в методе onCreate(Bundle)
     *
     * @param savedInstanceState bundle с агрументами
     */
    @Override
    public void onCreateActivity(Bundle savedInstanceState) {
        super.onCreateActivity(savedInstanceState);
        defaultTextColor = getResources().getColor(R.color.drawer_text_color);
        defaultCounterTextColor = getResources().getColor(R.color.drawer_item_counter_text_color);

        drawerAdapter = new DrawerAdapter(context);

        drawer = (DrawerLayout) findViewById(R.id.drawer);
        drawerLayout = (LinearLayout) drawer.findViewById(R.id.drawer_content);
        contentLayout = (FrameLayout) drawer.findViewById(R.id.activity_content);
        drawerListMenu = (RecyclerView) drawer.findViewById(R.id.drawer_recycler_view);
        contentPaddingTop = contentLayout.getPaddingTop();

        drawerListMenu.setLayoutManager(new LinearLayoutManager(context));
        drawerListMenu.setItemAnimator(new DefaultItemAnimator());
        drawerListMenu.setAdapter(drawerAdapter);
        drawerAdapter.setOnItemClickListener(this);

        showToolbar();

        contentLayout.addView(getLayoutInflater().inflate(getContentResource(), contentLayout, false), 0);

        initDrawer();

        calculateWidthDrawer();

        if (Build.VERSION.SDK_INT >= 19)
            drawerAdapter.setTransparentStatusBar((getWindow().getAttributes().flags &
                    WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS) != 0);
    }

    private void initDrawer() {
        mDrawerToggle = new ActionBarDrawerToggle(this, drawer,
                com.gsbelarus.gedemin.lib.R.string.navigation_drawer_open,
                com.gsbelarus.gedemin.lib.R.string.navigation_drawer_close) {
            @Override
            public void onDrawerStateChanged(int newState) {
                super.onDrawerStateChanged(newState);
                if (newState == 1)
                    activatedItem(selectedMainItem, drawerAdapter.getPositionItem(selectedMainItem));
                SyncActivityDrawerModel.this.onDrawerStateChanged(newState);
            }

            @Override
            public void onDrawerSlide(View drawerView, float slideOffset) {
                super.onDrawerSlide(drawerView, slideOffset);
                SyncActivityDrawerModel.this.onDrawerSlide(drawerView, slideOffset);
            }

            @Override
            public void onDrawerOpened(View drawerView) {
                super.onDrawerOpened(drawerView);
                SyncActivityDrawerModel.this.onDrawerOpened(drawerView);
            }

            @Override
            public void onDrawerClosed(View drawerView) {
                super.onDrawerClosed(drawerView);
                if (selectedOtherItem != null) {
                    onDrawerItemClickListener.onDrawerItemClick(selectedOtherItem);
                    selectedOtherItem = null;
                    return;
                }

                if (onClick) {
                    onClick = false;
                    onDrawerItemClickListener.onDrawerItemClick(selectedMainItem);
                }
                SyncActivityDrawerModel.this.onDrawerClosed(drawerView);
            }
        };

        drawer.setDrawerListener(mDrawerToggle);

        drawer.setDrawerShadow(R.drawable.drawer_shadow, Gravity.START);

        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
        getSupportActionBar().setHomeButtonEnabled(true);
    }

    private void showToolbar() {
        toolbar = (Toolbar) drawer.findViewById(R.id.activity_toolbar);
        if (toolbar == null) return;

        toolbar.setVisibility(View.VISIBLE);
        toolbar.hideOverflowMenu();
        setSupportActionBar(toolbar);

        showElevationToolbar(true);
        showContentPaddingTop(true);
    }

    /**
     * Срабатывает после нажатию на пункт меню drawer-а
     */
    @Override
    public void onItemClick(DrawerItem item, int position) {
        if (item.getType() == DrawerAdapter.ItemType.MAIN_ITEM) {
            selectedMainItem = item;
            activatedItem(selectedMainItem, position);
        } else
            selectedOtherItem = item;

        getDrawer().closeDrawers();
        onClick = true;
    }

    private void activatedItem(DrawerItem item, int position) {
        if (position == -1) return;

        for (int i = 0; i < drawerAdapter.getItemCount(); i++) {
            RecyclerView.ViewHolder viewHolder = drawerListMenu.findViewHolderForPosition(i);

            if (viewHolder instanceof DrawerAdapter.ProfileItemVH ||
                    viewHolder instanceof DrawerAdapter.DividerItemVH) continue;

            DrawerAdapter.DrawerItemVH vh = (DrawerAdapter.DrawerItemVH) viewHolder;
            if (vh != null) {
                vh.itemView.setActivated(false);
                vh.text.setTextColor(defaultTextColor);
                vh.counter.setTextColor(defaultCounterTextColor);
            }
        }

        for (DrawerItem drawerItem : drawerAdapter.getItems()) {
            if (!(drawerItem instanceof DrawerMainItem)) continue;

            DrawerMainItem drawerMainItem = (DrawerMainItem) drawerItem;
            Drawable image = drawerMainItem.getImage();
            if (image != null)
                image.setColorFilter(drawerMainItem.getDefaultDrawableColor(), PorterDuff.Mode.SRC_ATOP);
        }

        DrawerAdapter.DrawerItemVH viewHolder =
                (DrawerAdapter.DrawerItemVH) drawerListMenu.findViewHolderForPosition(position);
        if (viewHolder == null) return;

        viewHolder.itemView.setActivated(true);
        if (item.getActivatedColor() == 0) {
            viewHolder.text.setTextColor(defaultTextColor);
            viewHolder.counter.setTextColor(defaultTextColor);
        } else {
            viewHolder.text.setTextColor(item.getActivatedColor());
            viewHolder.counter.setTextColor(item.getActivatedColor());
        }
        if (item.getImage() != null)
            item.getImage().setColorFilter(item.getActivatedColor(), PorterDuff.Mode.SRC_ATOP);
    }

    /**
     * Расчет ширины NavigationDrawer исходя из рекомендаций google
     */
    private void calculateWidthDrawer() {
        TypedValue tv = new TypedValue();
        int toolbarHeight = 0;
        if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) {
            toolbarHeight = (int) (tv.getDimension(getResources().getDisplayMetrics()) / getResources().getDisplayMetrics().density);
            if (toolbarHeight > 0) {
                int drawerMaxWidth = (int) (getResources().getDimension(R.dimen.navigation_drawer_width_max) / getResources().getDisplayMetrics().density);
                Configuration configuration = getResources().getConfiguration();
                int screenWidthDp = configuration.screenWidthDp;
                int drawerWidth = screenWidthDp - toolbarHeight;

                ViewGroup.LayoutParams layout_description = drawerListMenu.getLayoutParams();
                layout_description.width = (int) TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
                        drawerWidth < drawerMaxWidth ? drawerWidth : drawerMaxWidth,
                        getResources().getDisplayMetrics());
                drawerListMenu.setLayoutParams(layout_description);
            }
        }
    }


    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        super.onConfigurationChanged(newConfig);
        if (mDrawerToggle != null)
            mDrawerToggle.onConfigurationChanged(newConfig);
    }

    @Override
    protected void onPostCreate(Bundle savedInstanceState) {
        super.onPostCreate(savedInstanceState);
        if (mDrawerToggle != null)
            mDrawerToggle.syncState();
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        if (mDrawerToggle != null && mDrawerToggle.onOptionsItemSelected(item))
            return true;
        return super.onOptionsItemSelected(item);
    }

    public void selectMainItem(DrawerItem item) {
        if (drawerAdapter.containsItem(item)) {
            selectedMainItem = item;
            activatedItem(selectedMainItem, drawerAdapter.getPositionItem(item));
            onDrawerItemClickListener.onDrawerItemClick(selectedMainItem);
        } else Log.d("selectMainItem", "drawer не содержит такого item");
    }

    public void selectMainItem(long id) {
        DrawerItem item = drawerAdapter.getItemById(id);
        if (item != null) {
            selectedMainItem = item;
            activatedItem(selectedMainItem, drawerAdapter.getPositionItem(item));
            onDrawerItemClickListener.onDrawerItemClick(selectedMainItem);
        } else Log.d("selectMainItem(long id)", "drawer не содержит item с таким id");
    }

    /**
     * Обновить элемент списка
     *
     * @param item элемент списка для обновления
     */
    public void notifyChangedItem(DrawerItem item) {
        drawerAdapter.notifyChangedItem(item);
    }

    /**
     * Обновить профиль
     */
    public void notifyChangedProfile() {
        drawerAdapter.notifyChangedProfile();
    }

    /**
     * Обновить все содержимое drawer меню
     */
    public void notifyDataChanged() {
        drawerAdapter.notifyDataSetChanged();
    }

    /**
     * Показать или скрыть (если profile == null) профиль
     *
     * @param profile объект хранящий данные для элемента profile. Если нужно убрать элемент, передавать null
     */
    public void setProfile(DrawerProfile profile) {
        drawerAdapter.setProfile(profile);
    }

    /**
     * Добавить элемент в меню drawer-а
     *
     * @param item элемент для добавления. DrawerDivider, DrawerMainItem, DrawerOtherItem
     */
    public void addItem(DrawerItem item) {
        drawerAdapter.addItem(item);
    }

    public void addItems(List<DrawerItem> items) {
        drawerAdapter.addItems(items);
    }

    /**
     * Удалить элемент из меню drawer-a
     */
    public void removeItem(DrawerItem item) {
        if (selectedMainItem == item) {
            if (!drawerAdapter.getItems().isEmpty())
                selectMainItem(drawerAdapter.getItems().get(0));
            else
                selectedMainItem = null;
        }
        drawerAdapter.removeItem(item);
    }

    public void clearAll() {
        selectedMainItem = null;
        drawerAdapter.clearAll();
    }

    public DrawerItem getItemById(long id) {
        return drawerAdapter.getItemById(id);
    }

    public DrawerProfile getProfile() {
        return drawerAdapter.getProfile();
    }

    protected OnDrawerItemClickListener getOnDrawerItemClickListener() {
        return onDrawerItemClickListener;
    }

    protected void setOnDrawerItemClickListener(OnDrawerItemClickListener onDrawerItemClickListener) {
        this.onDrawerItemClickListener = onDrawerItemClickListener;
    }

    @Override
    public void showContentPaddingTop(boolean flag) {
        if (!flag)
            super.showContentPaddingTop(flag);
        if (contentLayout != null) {
            contentLayout.setPadding(
                    contentLayout.getPaddingLeft(),
                    flag ? contentPaddingTop : 0,
                    contentLayout.getPaddingRight(),
                    contentLayout.getPaddingBottom());
            contentLayout.invalidate();
        }
    }

    public DrawerItem getSelectedMainItem() {
        return selectedMainItem;
    }

    public LinearLayout getDrawerLayout() {
        return drawerLayout;
    }

    public FrameLayout getContentLayout() {
        return contentLayout;
    }

    public DrawerLayout getDrawer() {
        return drawer;
    }

    public ActionBarDrawerToggle getDrawerToggle() {
        return mDrawerToggle;
    }

    public interface OnDrawerItemClickListener {

        /**
         * Срабатывает после нажатию на пункт меню drawer-а
         * Особенность: вызывается после закрытия drawer-а
         *
         * @param item элемент по которому был клик
         */
        void onDrawerItemClick(DrawerItem item);
    }

    @Override
    public void onBackPressed() {
        /** если по нажатию на кнопку назад Drawer находится в открытом состоянии, закрываем его не выходя из приложения */
        if (getDrawer().isDrawerOpen(GravityCompat.START))
            getDrawer().closeDrawers();
        else
            super.onBackPressed();
    }
}